﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Thauan_Juliano_World
{
    public class Camera
    {
        public Matrix View;
        public Matrix Projector;

        GraphicsDevice device;

        private Matrix Orientation;

        private float[] hAngle = new float[2];
        private float[] vAngle = new float[2];

        public Vector3[] positions = new Vector3[2];

        private bool mdown = false;
        private int oldmx;
        private int oldmy;
        private float oldha;
        private float oldva;

        private const float moveAcc = 0.1f;
        private const float lookAcc = 0.2f;
        private const float moveStep = 0.3f;
        private const float lookStep = 0.005f;

        public Camera(Game game, Vector3 position)
            : this(game, position, Vector3.Zero)
        {

        }

        public Camera(Game game, Vector3 position, Vector3 target)
            : this(game, position, target, Vector3.Up)
        {
        }

        public Camera(Game game, Vector3 position, Vector3 target, Vector3 up)
        {
            device = game.GraphicsDevice;
            this.positions[0] = this.positions[1] = position;
            var ratio = (float)game.Window.ClientBounds.Width / (float)game.Window.ClientBounds.Height;
            View = Matrix.CreateLookAt(position, target, up);
            Projector = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, ratio, 1, 100);
        }

        public void Update()
        {
            UpdateFromMouse();
            UpdateFromKeyboard();
            UpdateOrientation();
            Smooth();
            ViewCamera();
        }

        private void UpdateFromMouse()
        {
            MouseState mouseState = Mouse.GetState();

            if (!mdown)
            {
                oldmx = mouseState.X;
                oldmy = mouseState.Y;
                oldha = hAngle[1];
                oldva = vAngle[1];
                mdown = true;
            }
            else
            {
                hAngle[1] = oldha - (mouseState.X - oldmx) * lookStep;
                vAngle[1] = oldva + (mouseState.Y - oldmy) * lookStep;
                Mouse.SetPosition(device.Viewport.Width / 2, device.Viewport.Height / 2);
                mdown = false;
            }
        }
        private void UpdateFromKeyboard()
        {
            KeyboardState ks = Keyboard.GetState();
            if (ks.IsKeyDown(Keys.W))
                positions[1] += Orientation.Forward * moveStep;
            if (ks.IsKeyDown(Keys.S))
                positions[1] += Orientation.Backward * moveStep;
            if (ks.IsKeyDown(Keys.A))
                positions[1] += Orientation.Left * moveStep;
            if (ks.IsKeyDown(Keys.D))
                positions[1] += Orientation.Right * moveStep;
        }
        private void UpdateOrientation()
        {
            Orientation = Matrix.CreateRotationY(hAngle[0]);
            Orientation *= Matrix.CreateFromAxisAngle(Orientation.Left, vAngle[0]);
        }
        private void Smooth()
        {
            positions[0] = Vector3.Lerp(positions[0], positions[1], moveAcc);
            hAngle[0] = MathHelper.Lerp(hAngle[0], hAngle[1], lookAcc);
            vAngle[0] = MathHelper.Lerp(vAngle[0], vAngle[1], lookAcc);
        }
        private void ViewCamera()
        {
            this.View = Matrix.CreateLookAt(this.positions[0], this.positions[0] + Orientation.Forward, Orientation.Up);
        }
    }
    
}
